package demo;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JRadioButton;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileFilter;
import javax.swing.JComboBox;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Vector;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.JPopupMenu;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.JTabbedPane;
import java.awt.Font;
import javax.swing.UIManager;
import java.awt.Color;

public class TKCSDL extends JFrame {

	private Vector<String> tapThuocTinh = new Vector<String>();
	private Vector<Vector<Vector<String>>> tapPhuThuocHam = new Vector<Vector<Vector<String>>>();
	private Vector<String> vePhai = new Vector<String>();
	private Vector<String> veTrai = new Vector<String>();
	private Vector<String> tapConThuocTinh = new Vector<String>();
	private Vector<String> t1 = new Vector<String>();
	private Vector<String> t2 = new Vector<String>();
	private int[] binary;

	private JPanel contentPane;
	public static JComboBox comboBox;
	private JRadioButton radioButton;
	private JButton button;
	private JMenuBar menuBar;
	private JMenu mnFile;
	private JMenuItem mntmOpen;
	private JMenuItem mntmSave;
	private JTextArea textArea;
	private JPanel panel_3;
	private JComboBox comboBox_1;
	private JComboBox comboBox_2;
	private JButton btnNewButton;
	private JRadioButton rdbtnXong;
	private JTextField textField;
	private JTextArea textArea_1;
	private JComboBox comboBox_3;
	private JComboBox comboBox_4;
	private JTextArea textArea_2;
	private JScrollPane scrollPane_3;
	private JTextArea textArea_3;
	private JButton btnTmBaong;
	private JTextArea textArea_4;
	private JTextArea textArea_5;
	private JComboBox comboBox_5;
	private JComboBox comboBox_6;
	private JTextArea textArea_6;
	private JTextArea textArea_7;
	private JTextArea textArea_8;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TKCSDL frame = new TKCSDL();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public TKCSDL() {

		setTitle("Demo Thiết kế CSDL - Bùi Đức Kiên");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 908, 598);
		setLocationRelativeTo(null);
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);

		mnFile = new JMenu("File");
		menuBar.add(mnFile);

		mntmOpen = new JMenuItem("Open");
		mntmOpen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				openFile();
			}
		});
		mntmOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
				InputEvent.CTRL_MASK));
		mnFile.add(mntmOpen);

		mntmSave = new JMenuItem("Save");
		mntmSave.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				saveFile();
			}
		});
		mntmSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
				InputEvent.CTRL_MASK));
		mnFile.add(mntmSave);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);

		JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(UIManager
				.getBorder("TitledBorder.border"),
				"T\u1EADp thu\u1ED9c T\u00EDnh(Q)", TitledBorder.LEADING,
				TitledBorder.TOP, null, new Color(0, 70, 213)));

		button = new JButton("Thêm thuộc tính");
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				addField();
			}
		});

		radioButton = new JRadioButton("Xong");
		radioButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				comboBox.setEnabled(!radioButton.isSelected());
				button.setEnabled(!radioButton.isSelected());
			}
		});

		JPanel panel_1 = new JPanel();
		panel_1.setBorder(new TitledBorder(UIManager
				.getBorder("TitledBorder.border"),
				"T\u1EADp ph\u1EE5 thu\u1ED9c h\u00E0m(F)",
				TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 70,
						213)));

		comboBox_1 = new JComboBox();
		comboBox_1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (comboBox_1.getItemCount() != 0) {
					if (comboBox_1.getSelectedIndex() != 0) {
						String selected = comboBox_1.getSelectedItem()
								.toString();
						if (veTrai.contains(selected)) {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn xóa " + selected
											+ " khỏi Vế trái?", "Thông báo",
									JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								veTrai.removeElement(selected);
								comboBox_1.setSelectedIndex(0);
								textField.setText(((veTrai.size() != 0) ? toVectorString(veTrai)
										: "")
										+ " → "
										+ ((vePhai.size() != 0) ? toVectorString(vePhai)
												: ""));
							} else
								comboBox_1.setSelectedIndex(0);
							return;
						} else {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn thêm " + selected
											+ " vào Vế trái?", "Thông báo",
									JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								veTrai.add(selected);
								comboBox_1.setSelectedIndex(0);
								textField.setText(((veTrai.size() != 0) ? toVectorString(veTrai)
										: "")
										+ " → "
										+ ((vePhai.size() != 0) ? toVectorString(vePhai)
												: ""));
							} else
								comboBox_1.setSelectedIndex(0);
							return;
						}
					}
				}
			}
		});
		comboBox_1
				.setModel(new DefaultComboBoxModel(new String[] { "Vế trái" }));

		comboBox_2 = new JComboBox();
		comboBox_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (comboBox_2.getItemCount() != 0) {
					if (comboBox_2.getSelectedIndex() != 0) {
						String selected = comboBox_2.getSelectedItem()
								.toString();
						if (vePhai.contains(selected)) {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn xóa " + selected
											+ " khỏi Vế phải?", "Thông báo",
									JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								vePhai.removeElement(selected);
								comboBox_2.setSelectedIndex(0);
								textField.setText(((veTrai.size() != 0) ? toVectorString(veTrai)
										: "")
										+ " → "
										+ ((vePhai.size() != 0) ? toVectorString(vePhai)
												: ""));
							} else
								return;
						} else {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn thêm " + selected
											+ " vào Vế phải?", "Thông báo",
									JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								vePhai.add(selected);
								comboBox_2.setSelectedIndex(0);
								textField.setText(((veTrai.size() != 0) ? toVectorString(veTrai)
										: "")
										+ " → "
										+ ((vePhai.size() != 0) ? toVectorString(vePhai)
												: ""));
							} else
								comboBox_2.setSelectedIndex(0);
							return;
						}
					}
				}
			}
		});
		comboBox_2
				.setModel(new DefaultComboBoxModel(new String[] { "Vế phải" }));

		btnNewButton = new JButton("Thêm");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (vePhai.size() == 0 && veTrai.size() == 0) {
					JOptionPane.showMessageDialog(null,
							"Chưa nhập phụ thuộc hàm", "Thông báo",
							JOptionPane.WARNING_MESSAGE);
					return;
				}
				if (vePhai.size() != 0 && veTrai.size() == 0) {
					JOptionPane.showMessageDialog(null,
							"Chưa nhập Vế trái của phụ thuộc hàm", "Thông báo",
							JOptionPane.WARNING_MESSAGE);
					return;
				}
				if (vePhai.size() == 0 && veTrai.size() != 0) {
					JOptionPane.showMessageDialog(null,
							"Chưa nhập Vế phải của phụ thuộc hàm", "Thông báo",
							JOptionPane.WARNING_MESSAGE);
					return;
				}

				if (vePhai.size() != 0 && veTrai.size() != 0) {

					Vector<Vector<String>> tmpPhuThuocHam = new Vector<Vector<String>>();
					tmpPhuThuocHam.add(veTrai);
					tmpPhuThuocHam.add(vePhai);
					tapPhuThuocHam.add(tmpPhuThuocHam);
					showListPhuThuocHam();
					textField.setText("");

					vePhai = new Vector<String>();
					veTrai = new Vector<String>();
				}
			}
		});

		comboBox = new JComboBox();
		comboBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent act) {
				if (comboBox.getItemCount() != 0) {
					if (comboBox.getSelectedIndex() != 0)
						if (JOptionPane.showConfirmDialog(
								null,
								"Bạn muốn xóa thuộc tính "
										+ comboBox.getSelectedItem() + "?",
								"Thông báo", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
							int indexDelete = comboBox.getSelectedIndex();
							String s = textArea.getText();
							String str = comboBox.getSelectedItem().toString();
							if (tapThuocTinh.size() == 1)
								textArea.setText(s.replace(str, ""));
							else {
								if (indexDelete != tapThuocTinh.size())
									textArea.setText(s.replace(str + ",", ""));
								else
									textArea.setText(s.replace("," + str, ""));
							}
							tapThuocTinh.removeElementAt(indexDelete - 1);
							comboBox.removeItemAt(indexDelete);
							comboBox_1.removeItemAt(indexDelete);
							comboBox_2.removeItemAt(indexDelete);
							comboBox_4.removeItemAt(indexDelete);
							comboBox_5.removeItemAt(indexDelete);
							comboBox_6.removeItemAt(indexDelete);
						}
					comboBox.setSelectedIndex(0);
				}
			}
		});
		comboBox.setModel(new DefaultComboBoxModel(
				new String[] { "Xóa thuộc tính" }));

		JScrollPane scrollPane = new JScrollPane();

		textArea = new JTextArea();
		textArea.setEditable(false);
		textArea.setFont(new Font("Monospaced", Font.PLAIN, 16));
		scrollPane.setViewportView(textArea);

		JButton btnLuTrngThi = new JButton("Save");
		btnLuTrngThi.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				saveFile();
			}
		});

		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);

		JButton btnLoad = new JButton("Load");
		btnLoad.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				openFile();
			}
		});

		JButton btnHelp = new JButton("Help");
		btnHelp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				JOptionPane
						.showMessageDialog(
								null,
								"Chọn Thêm thuộc tính để nhập vào thuộc tính cần thêm."
										+ "\nThuộc tính cách nhau bởi dấu phẩy.\nChọn Load để ",
								"Thông báo", JOptionPane.ERROR_MESSAGE);
			}
		});

		JPanel panel_2 = new JPanel();
		tabbedPane.addTab("Bao đóng tập thuộc tính", null, panel_2, null);

		comboBox_4 = new JComboBox();
		comboBox_4.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (comboBox_4.getItemCount() != 0) {
					if (comboBox_4.getSelectedIndex() != 0) {
						String selected = comboBox_4.getSelectedItem()
								.toString();
						if (tapConThuocTinh.contains(selected)) {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn xóa " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								tapConThuocTinh.removeElement(selected);
								comboBox_4.setSelectedIndex(0);
								showTapCon(textArea_2, tapConThuocTinh);
							} else
								comboBox_4.setSelectedIndex(0);
							return;
						} else {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn thêm " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								tapConThuocTinh.add(selected);
								comboBox_4.setSelectedIndex(0);
								showTapCon(textArea_2, tapConThuocTinh);
							} else
								comboBox_4.setSelectedIndex(0);
							return;
						}
					}
				}
			}
		});
		comboBox_4.setModel(new DefaultComboBoxModel(
				new String[] { "Chọn thuộc tính" }));

		JScrollPane scrollPane_2 = new JScrollPane();

		scrollPane_3 = new JScrollPane();

		textArea_2 = new JTextArea();
		textArea_2.setEditable(false);
		textArea_2.setFont(new Font("Monospaced", Font.PLAIN, 16));
		scrollPane_2.setViewportView(textArea_2);

		btnTmBaong = new JButton("Tìm bao đóng");
		btnTmBaong.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				/*
				 * Tìm bao đóng của tập tính
				 */
				timBaoDongTapThuocTinh(tapConThuocTinh, tapPhuThuocHam, true,
						textArea_3);

			}
		});
		GroupLayout gl_panel_2 = new GroupLayout(panel_2);
		gl_panel_2
				.setHorizontalGroup(gl_panel_2
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_panel_2
										.createSequentialGroup()
										.addGap(10)
										.addGroup(
												gl_panel_2
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																comboBox_4,
																GroupLayout.PREFERRED_SIZE,
																133,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																btnTmBaong))
										.addGap(8)
										.addGroup(
												gl_panel_2
														.createParallelGroup(
																Alignment.TRAILING)
														.addComponent(
																scrollPane_3,
																GroupLayout.DEFAULT_SIZE,
																318,
																Short.MAX_VALUE)
														.addComponent(
																scrollPane_2,
																GroupLayout.DEFAULT_SIZE,
																318,
																Short.MAX_VALUE))
										.addContainerGap()));
		gl_panel_2.setVerticalGroup(gl_panel_2.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_panel_2
						.createSequentialGroup()
						.addGap(11)
						.addGroup(
								gl_panel_2
										.createParallelGroup(Alignment.LEADING)
										.addComponent(comboBox_4,
												GroupLayout.PREFERRED_SIZE,
												GroupLayout.DEFAULT_SIZE,
												GroupLayout.PREFERRED_SIZE)
										.addComponent(scrollPane_2,
												GroupLayout.PREFERRED_SIZE, 42,
												GroupLayout.PREFERRED_SIZE))
						.addGap(8)
						.addGroup(
								gl_panel_2
										.createParallelGroup(Alignment.LEADING)
										.addComponent(btnTmBaong)
										.addComponent(scrollPane_3,
												GroupLayout.DEFAULT_SIZE, 404,
												Short.MAX_VALUE)).addGap(14)));

		textArea_3 = new JTextArea();
		textArea_3.setEditable(false);
		textArea_3.setFont(new Font("Monospaced", Font.PLAIN, 16));
		scrollPane_3.setViewportView(textArea_3);
		panel_2.setLayout(gl_panel_2);

		JPanel panel_4 = new JPanel();
		tabbedPane.addTab("Khóa", null, panel_4, null);

		JButton btnTmKha = new JButton("Tìm khóa");
		btnTmKha.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				timKhoa();
			}
		});

		JScrollPane scrollPane_4 = new JScrollPane();
		GroupLayout gl_panel_4 = new GroupLayout(panel_4);
		gl_panel_4.setHorizontalGroup(gl_panel_4.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_panel_4
						.createSequentialGroup()
						.addGap(10)
						.addComponent(btnTmKha)
						.addGap(8)
						.addComponent(scrollPane_4, GroupLayout.DEFAULT_SIZE,
								372, Short.MAX_VALUE).addGap(14)));
		gl_panel_4.setVerticalGroup(gl_panel_4.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_panel_4
						.createSequentialGroup()
						.addGap(11)
						.addGroup(
								gl_panel_4
										.createParallelGroup(Alignment.LEADING)
										.addComponent(btnTmKha)
										.addComponent(scrollPane_4,
												GroupLayout.DEFAULT_SIZE, 452,
												Short.MAX_VALUE)).addGap(13)));

		textArea_4 = new JTextArea();
		textArea_4.setEditable(false);
		textArea_4.setFont(new Font("Monospaced", Font.PLAIN, 16));
		scrollPane_4.setViewportView(textArea_4);
		panel_4.setLayout(gl_panel_4);

		panel_3 = new JPanel();
		tabbedPane.addTab("Phủ tối thiểu", null, panel_3, null);

		JScrollPane scrollPane_5 = new JScrollPane();

		JButton btnTmPhTi = new JButton("Tìm phủ tối thiểu");
		btnTmPhTi.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (tapPhuThuocHam.size() == 0)
					return;
				textArea_5.setText("");
				textArea_5
						.append("  ●  Tìm phủ tối thiểu của tập phụ thuộc hàm F = {");
				for (int i = 0; i < tapPhuThuocHam.size() - 1; i++)
					textArea_5.append(toStringPTH(tapPhuThuocHam.get(i)) + ", ");
				textArea_5.append(toStringPTH(tapPhuThuocHam.get(tapPhuThuocHam
						.size() - 1)) + "}");
				textArea_5
						.append("\n  ●  Bước 1: Phân rã phụ thuộc hàm để vế phải còn 1 thuộc tính");
				boolean isPhanRa = false;
				Vector<Vector<Vector<String>>> phuToiThieu = new Vector<Vector<Vector<String>>>();
				// Duyệt phụ thuộc hàm
				for (Vector<Vector<String>> phuThuocHam : tapPhuThuocHam) {
					// Vế phải nhiều hơn 1 thuộc tính
					int numVePhai = phuThuocHam.get(1).size();
					if (numVePhai > 1) {
						textArea_5.append("\n    Vế phải của phụ thuộc hàm "
								+ toStringPTH(phuThuocHam) + " có " + numVePhai
								+ " thuộc tính");
						isPhanRa = true;
						textArea_5.append("\n    Phân rã "
								+ toStringPTH(phuThuocHam) + " thành "
								+ String.valueOf(numVePhai)
								+ " phụ thuộc hàm : \n        ");
						// Phân rã phụ thuộc hàm để vế phải còn 1 thuộc tính
						for (String thuocTinhVePhai : phuThuocHam.get(1)) {
							Vector<Vector<String>> tmpPhuThuocHam = new Vector<Vector<String>>();
							Vector<String> tmpVePhai = new Vector<String>();
							tmpVePhai.add(thuocTinhVePhai);
							tmpPhuThuocHam.add(phuThuocHam.get(0));
							tmpPhuThuocHam.add(tmpVePhai);
							phuToiThieu.add(tmpPhuThuocHam);
							textArea_5.append(toStringPTH(tmpPhuThuocHam)
									+ " ; ");
						}
						StringBuffer s = new StringBuffer(textArea_5.getText());
						s.deleteCharAt(s.length() - 2);
						textArea_5.setText(s.toString());
					} else {
						phuToiThieu.add(phuThuocHam);
					}
				}
				if (!isPhanRa) {
					textArea_5
							.append("\n    Không có phụ thuộc hàm nào có vế phải chứa nhiều hơn 1 thuộc tính. Bỏ qua bước 1.");
				}
				textArea_5
						.append("\n    Kết thúc bước 1, ta có tập phụ thuộc hàm :");
				for (Vector<Vector<String>> phuThuocHam : phuToiThieu) {
					textArea_5.append("\n        " + toStringPTH(phuThuocHam));
				}

				textArea_5
						.append("\n  ●  Bước 2 : Thay thế phụ thuộc hàm không đầy đủ bằng phụ thuộc hàm đầy đủ");

				//
				Vector<Vector<Vector<String>>> tmpPhuToiThieu = new Vector<Vector<Vector<String>>>();
				tmpPhuToiThieu.addAll(phuToiThieu);
				for (Vector<Vector<String>> phuThuocHam : phuToiThieu) {
					// số thuộc tính của vế trái phụ thuộc hàm
					textArea_5.append("\n    Xét phụ thuộc hàm "
							+ toStringPTH(phuThuocHam));
					int numVeTrai = phuThuocHam.get(0).size();
					if (numVeTrai > 1) {
						Vector<Vector<String>> tapVeTrai = new Vector<Vector<String>>();
						int insert = tmpPhuToiThieu.indexOf(phuThuocHam);
						tmpPhuToiThieu.removeElement(phuThuocHam);
						binary = new int[numVeTrai];
						Vector<Vector<String>> tapCon = new Vector<Vector<String>>();
						sinhTapCon(0, phuThuocHam.get(0), tapCon);
						for (Vector<String> con : tapCon) {
							if (con.size() == 0)
								continue;
							Vector<String> baoDong = new Vector<String>();
							baoDong.addAll(timBaoDongTapThuocTinh(con,
									tmpPhuToiThieu, false, null));
							if (tapCon(phuThuocHam.get(1), baoDong)) {
								tapVeTrai.add(con);
							}
						}

						if (tapVeTrai.size() > 1) {
							textArea_5.append("\n        Phụ thuộc hàm "
									+ toStringPTH(phuThuocHam)
									+ " là phụ hàm không đầy đủ, vì : ");
							int minSize = numVeTrai;
							for (Vector<String> con : tapVeTrai) {
								if (con.size() < minSize)
									minSize = con.size();
							}
							Vector<String> tmpCon = new Vector<String>();
							for (Vector<String> con : tapVeTrai) {
								if (con.size() == minSize) {
									tmpCon = new Vector<String>();
									tmpCon.addAll(con);
									break;
								}
							}
							textArea_5.append("\n        "
									+ toVectorString(tmpCon)
									+ " → "
									+ toVectorString(phuThuocHam.get(1))
									+ " có thể suy diễn được từ tập phụ thuộc hàm cũ loại bỏ phụ thuộc hàm "
									+ toStringPTH(phuThuocHam)
									+ "\n        Thay "
									+ toStringPTH(phuThuocHam) + " bằng "
									+ toVectorString(tmpCon) + " → "
									+ toVectorString(phuThuocHam.get(1)));
							Vector<Vector<String>> tmpPhuThuocHam = new Vector<Vector<String>>();
							tmpPhuThuocHam.add(tmpCon);
							tmpPhuThuocHam.add(phuThuocHam.get(1));
							tmpPhuToiThieu.insertElementAt(tmpPhuThuocHam,
									insert);
						} else {
							textArea_5
									.append("\n        Phụ thuộc hàm "
											+ toStringPTH(phuThuocHam)
											+ " là phụ thuộc hàm đầy đủ vì không thể bỏ đi thuộc tính nào ở vế trái");
							tmpPhuToiThieu.insertElementAt(phuThuocHam, insert);
						}
					} else {
						textArea_5
								.append("\n        Vế trái chỉ có 1 thuộc tính");
					}
				}
				textArea_5
						.append("\n    Kết thúc bước 2, ta có tập phụ thuộc hàm :");
				for (Vector<Vector<String>> phuThuocHam : tmpPhuToiThieu) {
					textArea_5.append("\n        " + toStringPTH(phuThuocHam));
				}
				textArea_5
						.append("\n  ●  Bước 3: Loại bỏ các phụ thuộc hàm thừa");
				phuToiThieu = new Vector<Vector<Vector<String>>>();
				phuToiThieu.addAll(tmpPhuToiThieu);
				for (Vector<Vector<String>> phuThuocHam : phuToiThieu) {
					textArea_5.append("\n    Xét phụ thuộc hàm "
							+ toStringPTH(phuThuocHam));
					int insert = tmpPhuToiThieu.indexOf(phuThuocHam);
					tmpPhuToiThieu.removeElement(phuThuocHam);
					Vector<String> baoDongVeTrai = timBaoDongTapThuocTinh(
							phuThuocHam.get(0), tmpPhuToiThieu, false, null);
					if (tapCon(phuThuocHam.get(1), baoDongVeTrai)) {
						textArea_5.append("\n        "
								+ toStringPTH(phuThuocHam)
								+ " là phụ thuộc hàm dư thừa");
						textArea_5.append("\n    Bỏ "
								+ toStringPTH(phuThuocHam)
								+ " , ta có tập phụ thuộc hàm :");
						for (Vector<Vector<String>> phuThuocHam1 : tmpPhuToiThieu) {
							textArea_5.append("\n        "
									+ toStringPTH(phuThuocHam1));
						}
					} else {
						textArea_5.append("\n       "
								+ toStringPTH(phuThuocHam)
								+ " không phải phụ thuộc hàm dư thừa");
						tmpPhuToiThieu.insertElementAt(phuThuocHam, insert);
					}
				}
				textArea_5.append("\n  ●  Vậy phủ tối thiểu tìm được là : ");
				for (Vector<Vector<String>> phuThuocHam : tmpPhuToiThieu) {
					textArea_5.append("\n    " + toStringPTH(phuThuocHam));
				}
			}
		});
		GroupLayout gl_panel_3 = new GroupLayout(panel_3);
		gl_panel_3.setHorizontalGroup(gl_panel_3.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_panel_3
						.createSequentialGroup()
						.addContainerGap()
						.addGroup(
								gl_panel_3
										.createParallelGroup(Alignment.LEADING)
										.addComponent(scrollPane_5,
												GroupLayout.DEFAULT_SIZE, 510,
												Short.MAX_VALUE)
										.addComponent(btnTmPhTi))
						.addContainerGap()));
		gl_panel_3.setVerticalGroup(gl_panel_3.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_panel_3
						.createSequentialGroup()
						.addContainerGap()
						.addComponent(btnTmPhTi)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(scrollPane_5, GroupLayout.DEFAULT_SIZE,
								410, Short.MAX_VALUE).addContainerGap()));

		textArea_5 = new JTextArea();
		textArea_5.setFont(new Font("Monospaced", Font.PLAIN, 16));
		textArea_5.setEditable(false);
		scrollPane_5.setViewportView(textArea_5);
		panel_3.setLayout(gl_panel_3);
		GroupLayout gl_panel = new GroupLayout(panel);
		gl_panel.setHorizontalGroup(gl_panel
				.createParallelGroup(Alignment.LEADING)
				.addGroup(
						gl_panel.createSequentialGroup()
								.addGap(10)
								.addGroup(
										gl_panel.createParallelGroup(
												Alignment.LEADING)
												.addGroup(
														gl_panel.createSequentialGroup()
																.addComponent(
																		button)
																.addGap(6)
																.addComponent(
																		comboBox,
																		GroupLayout.PREFERRED_SIZE,
																		111,
																		GroupLayout.PREFERRED_SIZE)
																.addGap(2)
																.addComponent(
																		radioButton))
												.addComponent(
														scrollPane,
														GroupLayout.PREFERRED_SIZE,
														237,
														GroupLayout.PREFERRED_SIZE))));
		gl_panel.setVerticalGroup(gl_panel
				.createParallelGroup(Alignment.LEADING)
				.addGroup(
						gl_panel.createSequentialGroup()
								.addGroup(
										gl_panel.createParallelGroup(
												Alignment.LEADING)
												.addComponent(button)
												.addGroup(
														gl_panel.createSequentialGroup()
																.addGap(1)
																.addComponent(
																		comboBox,
																		GroupLayout.PREFERRED_SIZE,
																		GroupLayout.DEFAULT_SIZE,
																		GroupLayout.PREFERRED_SIZE))
												.addComponent(radioButton))
								.addGap(11)
								.addComponent(scrollPane,
										GroupLayout.PREFERRED_SIZE, 42,
										GroupLayout.PREFERRED_SIZE)));
		panel.setLayout(gl_panel);

		JButton btnNew = new JButton("New");
		btnNew.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (JOptionPane
						.showConfirmDialog(
								null,
								"Bạn muốn tạo 1 trạng thái dữ liệu mới?\nViệc chọn Yes có thể làm mất trạng thái dữ liệu hiện tại",
								"Thông báo", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
					tapThuocTinh = new Vector<String>();
					tapPhuThuocHam = new Vector<Vector<Vector<String>>>();
					vePhai = new Vector<String>();
					veTrai = new Vector<String>();
					tapConThuocTinh = new Vector<String>();
					button.setEnabled(true);
					btnNewButton.setEnabled(true);
					comboBox.removeAllItems();
					comboBox.addItem("Xóa thuộc tính");
					comboBox.setEnabled(true);
					comboBox_1.removeAllItems();
					comboBox_1.addItem("Vế trái");
					comboBox_1.setEnabled(true);
					comboBox_2.removeAllItems();
					comboBox_2.setEnabled(true);
					comboBox_2.addItem("Vế phải");
					comboBox_3.removeAllItems();
					comboBox_3.addItem("Xóa phụ thuộc hàm");
					comboBox_3.setEnabled(true);
					comboBox_4.removeAllItems();
					comboBox_4.addItem("Chọn thuộc tính");
					radioButton.setSelected(false);
					rdbtnXong.setSelected(false);
					textArea.setText("");
					textArea_1.setText("");
					textArea_2.setText("");
					textArea_3.setText("");
					textArea_4.setText("");
					textArea_5.setText("");

				}
			}
		});

		rdbtnXong = new JRadioButton("Xong");
		rdbtnXong.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				comboBox_3.setEnabled(!rdbtnXong.isSelected());
				btnNewButton.setEnabled(!rdbtnXong.isSelected());
				comboBox_1.setEnabled(!rdbtnXong.isSelected());
				comboBox_2.setEnabled(!rdbtnXong.isSelected());
				textField.setText("");
				veTrai = new Vector<String>();
				vePhai = new Vector<String>();
			}
		});

		JScrollPane scrollPane_1 = new JScrollPane();

		textField = new JTextField();
		textField.setEditable(false);
		textField.setColumns(10);

		comboBox_3 = new JComboBox();
		comboBox_3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (comboBox_3.getItemCount() != 0) {
					if (comboBox_3.getSelectedIndex() != 0)
						if (JOptionPane.showConfirmDialog(
								null,
								"Bạn muốn xóa phụ thuộc hàm "
										+ comboBox_3.getSelectedItem() + "?",
								"Thông báo", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
							int selected = comboBox_3.getSelectedIndex();
							
							tapPhuThuocHam.removeElementAt(selected - 1);
							comboBox_3.removeItemAt(selected);
							showListPhuThuocHam();
						}
					comboBox_3.setSelectedIndex(0);
				}
			}
		});
		comboBox_3.setModel(new DefaultComboBoxModel(
				new String[] { "Xóa phụ thuộc hàm" }));
		GroupLayout gl_panel_1 = new GroupLayout(panel_1);
		gl_panel_1.setHorizontalGroup(gl_panel_1
				.createParallelGroup(Alignment.LEADING)
				.addGroup(
						gl_panel_1
								.createSequentialGroup()
								.addGap(10)
								.addComponent(scrollPane_1,
										GroupLayout.PREFERRED_SIZE, 289,
										GroupLayout.PREFERRED_SIZE)
								.addContainerGap())
				.addGroup(
						gl_panel_1
								.createSequentialGroup()
								.addContainerGap()
								.addComponent(btnNewButton)
								.addPreferredGap(ComponentPlacement.RELATED)
								.addComponent(comboBox_3, 0, 173,
										Short.MAX_VALUE)
								.addPreferredGap(ComponentPlacement.RELATED)
								.addComponent(rdbtnXong).addGap(10))
				.addGroup(
						gl_panel_1
								.createSequentialGroup()
								.addContainerGap()
								.addComponent(comboBox_1,
										GroupLayout.PREFERRED_SIZE, 125,
										GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(ComponentPlacement.RELATED,
										38, Short.MAX_VALUE)
								.addComponent(comboBox_2,
										GroupLayout.PREFERRED_SIZE, 125,
										GroupLayout.PREFERRED_SIZE).addGap(11))
				.addGroup(
						gl_panel_1
								.createSequentialGroup()
								.addContainerGap()
								.addComponent(textField,
										GroupLayout.PREFERRED_SIZE, 289,
										GroupLayout.PREFERRED_SIZE)
								.addContainerGap(GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE)));
		gl_panel_1
				.setVerticalGroup(gl_panel_1
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_panel_1
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_panel_1
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																comboBox_2,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																comboBox_1,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addComponent(textField,
												GroupLayout.PREFERRED_SIZE,
												GroupLayout.DEFAULT_SIZE,
												GroupLayout.PREFERRED_SIZE)
										.addGap(16)
										.addGroup(
												gl_panel_1
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(rdbtnXong)
														.addComponent(
																btnNewButton)
														.addComponent(
																comboBox_3,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addComponent(scrollPane_1,
												GroupLayout.DEFAULT_SIZE, 82,
												Short.MAX_VALUE).addGap(8)));
		gl_panel_1.linkSize(SwingConstants.HORIZONTAL, new Component[] {
				scrollPane_1, textField });

		textArea_1 = new JTextArea();
		textArea_1.setFont(new Font("Monospaced", Font.PLAIN, 16));
		textArea_1.setEditable(false);
		scrollPane_1.setViewportView(textArea_1);
		panel_1.setLayout(gl_panel_1);
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(
			gl_contentPane.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addGap(10)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_contentPane.createSequentialGroup()
							.addGap(18)
							.addComponent(btnLoad)
							.addGap(6)
							.addComponent(btnNew)
							.addGap(6)
							.addComponent(btnLuTrngThi)
							.addGap(6)
							.addComponent(btnHelp))
						.addComponent(panel_1, GroupLayout.PREFERRED_SIZE, 323, GroupLayout.PREFERRED_SIZE)
						.addComponent(panel, GroupLayout.PREFERRED_SIZE, 323, GroupLayout.PREFERRED_SIZE))
					.addGap(10)
					.addComponent(tabbedPane)
					.addGap(8))
		);
		gl_contentPane.setVerticalGroup(
			gl_contentPane.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addGap(11)
					.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
						.addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE)
						.addGroup(gl_contentPane.createSequentialGroup()
							.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
								.addComponent(btnLoad)
								.addComponent(btnNew)
								.addComponent(btnLuTrngThi)
								.addComponent(btnHelp))
							.addGap(19)
							.addComponent(panel, GroupLayout.PREFERRED_SIZE, 115, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.UNRELATED)
							.addComponent(panel_1, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE)))
					.addContainerGap())
		);

		JPanel panel_5 = new JPanel();
		tabbedPane.addTab("Dạng chuẩn", null, panel_5, null);

		comboBox_5 = new JComboBox();
		comboBox_5.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (comboBox_5.getItemCount() != 0) {
					if (comboBox_5.getSelectedIndex() != 0) {
						String selected = comboBox_5.getSelectedItem()
								.toString();
						if (t1.contains(selected)) {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn xóa " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								t1.removeElement(selected);
								comboBox_5.setSelectedIndex(0);
								showTapCon(textArea_6, t1);
							} else
								comboBox_5.setSelectedIndex(0);
							return;
						} else {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn thêm " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								t1.add(selected);
								comboBox_5.setSelectedIndex(0);
								showTapCon(textArea_6, t1);
							} else
								comboBox_5.setSelectedIndex(0);
							return;
						}
					}
				}
			}
		});
		comboBox_5.setModel(new DefaultComboBoxModel(
				new String[] { "Chọn thuộc tính" }));

		comboBox_6 = new JComboBox();
		comboBox_6.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (comboBox_6.getItemCount() != 0) {
					if (comboBox_6.getSelectedIndex() != 0) {
						String selected = comboBox_6.getSelectedItem()
								.toString();
						if (t2.contains(selected)) {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn xóa " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								t2.removeElement(selected);
								comboBox_6.setSelectedIndex(0);
								showTapCon(textArea_7, t2);
							} else
								comboBox_6.setSelectedIndex(0);
							return;
						} else {
							if (JOptionPane.showConfirmDialog(null,
									"Bạn muốn thêm " + selected + " ?",
									"Thông báo", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
								t2.add(selected);
								comboBox_6.setSelectedIndex(0);
								showTapCon(textArea_7, t2);
							} else
								comboBox_6.setSelectedIndex(0);
							return;
						}
					}
				}
			}
		});
		comboBox_6.setModel(new DefaultComboBoxModel(
				new String[] { "Chọn thuộc tính" }));

		textArea_6 = new JTextArea();

		textArea_7 = new JTextArea();

		textArea_8 = new JTextArea();

		JButton btnKimTra = new JButton("Kiểm tra");
		GroupLayout gl_panel_5 = new GroupLayout(panel_5);
		gl_panel_5
				.setHorizontalGroup(gl_panel_5
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_panel_5
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_panel_5
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																textArea_8,
																GroupLayout.DEFAULT_SIZE,
																510,
																Short.MAX_VALUE)
														.addGroup(
																gl_panel_5
																		.createSequentialGroup()
																		.addComponent(
																				comboBox_5,
																				GroupLayout.PREFERRED_SIZE,
																				111,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				textArea_6,
																				GroupLayout.PREFERRED_SIZE,
																				392,
																				GroupLayout.PREFERRED_SIZE))
														.addGroup(
																gl_panel_5
																		.createSequentialGroup()
																		.addComponent(
																				comboBox_6,
																				GroupLayout.PREFERRED_SIZE,
																				111,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				textArea_7,
																				GroupLayout.PREFERRED_SIZE,
																				392,
																				GroupLayout.PREFERRED_SIZE))
														.addComponent(btnKimTra))
										.addContainerGap()));
		gl_panel_5
				.setVerticalGroup(gl_panel_5
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_panel_5
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_panel_5
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																comboBox_5,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																textArea_6,
																GroupLayout.PREFERRED_SIZE,
																29,
																GroupLayout.PREFERRED_SIZE))
										.addPreferredGap(
												ComponentPlacement.UNRELATED)
										.addGroup(
												gl_panel_5
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																comboBox_6,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																textArea_7,
																GroupLayout.PREFERRED_SIZE,
																29,
																GroupLayout.PREFERRED_SIZE))
										.addGap(18)
										.addComponent(textArea_8,
												GroupLayout.PREFERRED_SIZE,
												104, GroupLayout.PREFERRED_SIZE)
										.addGap(18).addComponent(btnKimTra)
										.addContainerGap(219, Short.MAX_VALUE)));
		panel_5.setLayout(gl_panel_5);
		contentPane.setLayout(gl_contentPane);
	}

	/**
	 * Thêm thuộc tính Có thể thêm 1 hoặc nhiều thuộc tính Mỗi thuộc tính cách
	 * nhau bởi dấu phẩy
	 */
	public void addField() {
		String tapThuocTinhThem[] = null;
		try {
			tapThuocTinhThem = JOptionPane
					.showInputDialog(
							this,
							"Nhập vào tập thuộc tính. Thuộc tính không có dấu cách và cách nhau bởi dấu phẩy",
							"Nhập", JOptionPane.INFORMATION_MESSAGE).split(",");
		} catch (NullPointerException e) {
			return;
		}
		if (tapThuocTinhThem[0].length() == 0) {
			JOptionPane.showMessageDialog(this, "Chưa nhập thuộc tính.",
					"Thông báo", JOptionPane.ERROR_MESSAGE);
			return;
		}
		updateData(tapThuocTinhThem);
	}

	/*
	 * Trả về 1 tập con của tapCha
	 */
	public Vector<String> result(Vector<String> tapCha) {
		Vector<String> tmp = new Vector<String>();
		for (int i = 0; i < tapCha.size(); i++) {
			if (binary[i] == 1) {
				tmp.add(tapCha.get(i));
			}
		}
		return tmp;
	}

	/**
	 * Sinh các tập con của tapCha Các tập con lưu trong tapCon Khi cần sinh tập
	 * con gọi sinhTapCon(0, tapCha, tapCon);
	 * 
	 * @param i
	 * @param tapCha
	 * @param tapCon
	 */
	public void sinhTapCon(int i, Vector<String> tapCha,
			Vector<Vector<String>> tapCon) {
		int j = 0;
		for (j = 0; j <= 1; j++) {

			binary[i] = j;
			if (i == tapCha.size() - 1) {
				tapCon.add(result(tapCha));
			} else
				sinhTapCon(i + 1, tapCha, tapCon);
		}
	}

	/**
	 * Nhập dữ liệu có sẵn trong file
	 */
	public void openFile() {

		JFileChooser fileChooser = getFileChooser("Load file");
		int returnValue = fileChooser.showOpenDialog(this);
		if (returnValue == JFileChooser.APPROVE_OPTION) {
			File selectedFile = fileChooser.getSelectedFile();
			ObjectInput in = null;
			try {
				in = new ObjectInputStream(new FileInputStream(selectedFile));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Vector<String> tmpTapThuocTinh = null;
			Vector<Vector<Vector<String>>> tmpTapPhuThuocHam = new Vector<Vector<Vector<String>>>();
			Vector<Vector<Vector<String>>> tmptapPhuThuocHam = new Vector<Vector<Vector<String>>>();
			try {
				tmpTapThuocTinh = (Vector<String>) in.readObject();
				tmptapPhuThuocHam = (Vector<Vector<Vector<String>>>) in
						.readObject();
				btnNewButton.setEnabled(false);
				comboBox_3.setEnabled(false);
				rdbtnXong.setSelected(true);
				button.setEnabled(false);
				comboBox.setEnabled(false);
				radioButton.setSelected(true);
				comboBox_1.setEnabled(false);
				comboBox_2.setEnabled(false);
				textField.setText("");
			} catch (ClassNotFoundException e) {

			} catch (IOException e) {

			} catch (NullPointerException e) {
				JOptionPane.showMessageDialog(this, "File dữ liệu lỗi.",
						"Thông báo", JOptionPane.ERROR_MESSAGE);
			}
			updateData(toArrString(tmpTapThuocTinh));
			if (tapPhuThuocHam.size() == 0) {
				tapPhuThuocHam = tmptapPhuThuocHam;
				showListPhuThuocHam();
			}

		}
	}

	/**
	 * Lưu dữ liệu vào file
	 */
	public void saveFile() {
		if (JOptionPane.showConfirmDialog(this,
				"Bạn muốn lưu trạng thái dữ liệu hiện tại", "Thông báo",
				JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
			return;
		}
		JFileChooser fileChooser = getFileChooser("Save file");
		int returnValue = fileChooser.showSaveDialog(this);
		if (returnValue == JFileChooser.APPROVE_OPTION) {
			File selectedFile = fileChooser.getSelectedFile();
			ObjectOutput out = null;
			try {
				out = new ObjectOutputStream(new FileOutputStream(selectedFile));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				out.writeObject(tapThuocTinh);
				out.writeObject(tapPhuThuocHam);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}

	/**
	 * Cập nhật lại các thuộc tính trong các Combo Box khi thêm hoặc xóa thuộc
	 * tính
	 * 
	 * @param tapThuocTinhThem
	 */
	public void updateData(String[] tapThuocTinhThem) {
		StringBuffer exist = new StringBuffer();
		StringBuffer added = new StringBuffer();
		for (String thuocTinh : tapThuocTinhThem) {
			if (!tapThuocTinh.contains(thuocTinh.toUpperCase())) {
				tapThuocTinh.add(thuocTinh.toUpperCase());
				textArea.append(((textArea.getText().length() != 0) ? "," : "")
						+ thuocTinh.toUpperCase());
				added.append(thuocTinh.toUpperCase() + ",");

				comboBox.addItem(thuocTinh.toUpperCase());
				comboBox_1.addItem(thuocTinh.toUpperCase());
				comboBox_2.addItem(thuocTinh.toUpperCase());
				comboBox_4.addItem(thuocTinh.toUpperCase());
				comboBox_5.addItem(thuocTinh.toUpperCase());
				comboBox_6.addItem(thuocTinh.toUpperCase());

			} else {
				exist.append(thuocTinh.toUpperCase() + ",");
			}
		}
		if (exist.length() != 0 && added.length() == 0) {
			exist.deleteCharAt(exist.length() - 1);
			JOptionPane.showMessageDialog(this,
					"Thuộc tính " + exist.toString() + " đã tồn tại",
					"Thông báo", JOptionPane.INFORMATION_MESSAGE);
			return;
		}
		if (exist.length() != 0 && added.length() != 0) {
			exist.deleteCharAt(exist.length() - 1);
			added.deleteCharAt(added.length() - 1);
			JOptionPane.showMessageDialog(
					this,
					"Thuộc tính " + exist.toString()
							+ " đã tồn tại\nĐã thêm vào thuộc tính "
							+ added.toString(), "Thông báo",
					JOptionPane.INFORMATION_MESSAGE);
			return;
		}
		if (exist.length() == 0 && added.length() != 0) {
			added.deleteCharAt(added.length() - 1);
			JOptionPane.showMessageDialog(this, "Đã thêm vào thuộc tính "
					+ added.toString(), "Thông báo",
					JOptionPane.INFORMATION_MESSAGE);
			return;
		}
	}

	/**
	 * Hiện thị và cập nhật phụ thuộc hàm vào Combox khi người dùng cần xóa phụ
	 * thuộc hàm
	 */
	public void showListPhuThuocHam() {
		textArea_1.setText("");
		if (comboBox_3.getItemCount() > 1) {
			comboBox_3.removeAllItems();
			comboBox_3.addItem("Xóa phụ thuộc hàm");
		}
		// Duyệt từng phụ thuộc hàm
		for (Vector<Vector<String>> phuThuocHam : tapPhuThuocHam) {

			StringBuffer pth = new StringBuffer();
			// Duyệt vế trái phụ thuộc hàm
			for (String s : phuThuocHam.get(0)) {
				pth.append(s + ",");
			}
			pth.deleteCharAt(pth.length() - 1);
			pth.append(" → ");
			// Duyệt vế phải phụ thuộc hàm
			for (String s : phuThuocHam.get(1)) {
				pth.append(s + ",");
			}
			pth.deleteCharAt(pth.length() - 1);
			comboBox_3.addItem(pth);
			textArea_1.append(pth.toString() + "\n");
		}

	}

	/**
	 * Hiển thị 1 tập thuộc tính ra JTextArea
	 * 
	 * @param showContent
	 * @param content
	 */
	public void showTapCon(JTextArea showContent, Vector<String> content) {
		showContent.setText("");
		if (content.size() != 0) {
			StringBuffer pth = new StringBuffer();
			for (String s : content) {
				pth.append(s + ",");
			}
			pth.deleteCharAt(pth.length() - 1);
			showContent.setText(pth.toString());
		}
	}

	/**
	 * Đổi Vector<String> thành String[]
	 * 
	 * @param tempVector
	 * @return
	 */
	public String[] toArrString(Vector<String> tempVector) {
		String[] tmpArrString = new String[tempVector.size()];
		for (int i = 0; i < tempVector.size(); i++) {
			tmpArrString[i] = tempVector.get(i);
		}
		return tmpArrString;
	}

	/**
	 * Chuyển phụ thuộc hàm thành chuỗi
	 * 
	 * @param phuThuocHam
	 * @return
	 */
	public String toStringPTH(Vector<Vector<String>> phuThuocHam) {
		StringBuffer tmp = new StringBuffer();
		for (String s : phuThuocHam.get(0))
			tmp.append(s + ",");
		tmp.deleteCharAt(tmp.length() - 1);
		tmp.append(" → ");
		for (String str : phuThuocHam.get(1))
			tmp.append(str + ",");
		tmp.deleteCharAt(tmp.length() - 1);
		return tmp.toString();
	}

	/**
	 * Chuyển tập thuộc tính thành chuỗi để phục vụ việc in thông tin
	 * 
	 * @param vectorString
	 * @return
	 */
	public String toVectorString(Vector<String> vectorString) {
		StringBuffer tmp = new StringBuffer();
		for (String s : vectorString)
			tmp.append(s + ",");
		tmp.deleteCharAt(tmp.length() - 1);
		return tmp.toString();
	}

	/**
	 * Kiểm tra tập a có là tập con của tập b không
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	public boolean tapCon(Vector<String> a, Vector<String> b) {
		if (b.size() == 0)
			return false; // hay không
		if (a.size() > b.size())
			return false;
		else
			for (int i = 0; i < a.size(); i++) {
				if (!b.contains(a.get(i)))
					return false;
			}
		return true;
	}

	/**
	 * Kiểm tra a có phụ thuộc đầy đủ vào b không
	 * 
	 * @param a
	 * @param b
	 */
	public boolean phuThuocHamDayDu(Vector<String> a, Vector<String> b) {
		Vector<String> baoDong = timBaoDongTapThuocTinh(b, tapPhuThuocHam,
				false, null);
		if (tapCon(baoDong, a)) {
			Vector<Vector<String>> conB = new Vector<Vector<String>>();
			sinhTapCon(0, b, conB);
			for (Vector<String> con : conB) {
				Vector<String> baoDongCon = timBaoDongTapThuocTinh(con,
						tapPhuThuocHam, false, null);
				if (tapCon(baoDong, baoDongCon) && (con.size() != b.size()))
					return false;
			}
		} else {
			return false;
		}
		return true;
	}

	/**
	 * Tìm bao đóng của tập thuộc tính
	 * 
	 * @param tapConThuocTinh
	 * @param tapPhuThuocHam
	 * @param iShhow
	 * @param showHere
	 * @return
	 */
	public Vector<String> timBaoDongTapThuocTinh(
			Vector<String> tapConThuocTinh,
			Vector<Vector<Vector<String>>> tapPhuThuocHam, boolean iShhow,
			JTextArea showHere) {
		Vector<String> baoDongTapThuocTinh = new Vector<String>();
		if (tapConThuocTinh.size() == 0)
			return baoDongTapThuocTinh;
		if (iShhow) {
			showHere.setText("");
			showHere.append("  ●●  Cho quan hệ Q = ("
					+ toVectorString(tapThuocTinh)
					+ ") và tập phụ thuộc hàm F = {");
			for (int i = 0; i < tapPhuThuocHam.size() - 1; i++)
				showHere.append(toStringPTH(tapPhuThuocHam.get(i)) + ", ");
			showHere.append(toStringPTH(tapPhuThuocHam.get(tapPhuThuocHam
					.size() - 1))
					+ "} . Tìm bao đóng của tập thuộc tính "
					+ toVectorString(tapConThuocTinh));
		}
		baoDongTapThuocTinh.addAll(tapConThuocTinh);
		if (iShhow)
			showHere.append("\n\n  ●●  (" + toVectorString(tapConThuocTinh)
					+ ")+ = {" + toVectorString(baoDongTapThuocTinh) + "}\n\n");
		if (tapCon(baoDongTapThuocTinh, tapThuocTinh)
				&& tapCon(tapThuocTinh, baoDongTapThuocTinh)) {
			if (iShhow) {
				showHere.append("  ●●  Dừng giải thuật do ("
						+ toVectorString(tapConThuocTinh)
						+ ")+ bằng tập thuộc tính.\n\n  ●●  Vậy ("
						+ toVectorString(tapConThuocTinh) + ")+ ={"
						+ toVectorString(baoDongTapThuocTinh) + "}");
				return baoDongTapThuocTinh;
			}
		}
		boolean tt = true;
		if (iShhow)
			showHere.append("  ●●  Duyệt qua tập phụ thuộc hàm\n\n");
		while (tt == true) {
			Vector<String> tmp = new Vector<String>();
			tmp.addAll(baoDongTapThuocTinh);
			if (iShhow)
				showHere.append("      ●" + "("
						+ toVectorString(tapConThuocTinh) + ")+ = {"
						+ toVectorString(baoDongTapThuocTinh) + "}\n\n");
			for (Vector<Vector<String>> phuThuocHam : tapPhuThuocHam) {
				if (iShhow)
					showHere.append("      ●  Xét phụ thuộc hàm "
							+ toStringPTH(phuThuocHam) + " :\n");
				try {
					if (tapCon(phuThuocHam.get(0), baoDongTapThuocTinh)) {
						if (iShhow)
							showHere.append("           " + "("
									+ toVectorString(tapConThuocTinh)
									+ ")+ = {"
									+ toVectorString(baoDongTapThuocTinh) + "}"
									+ " chứa vế trái của phu thuộc hàm "
									+ toStringPTH(phuThuocHam)
									+ "\n           ");
						for (String str : phuThuocHam.get(1)) {
							if (!baoDongTapThuocTinh.contains(str)) {
								baoDongTapThuocTinh.add(str);
							}
						}
						if (iShhow)
							showHere.append("("
									+ toVectorString(tapConThuocTinh)
									+ ")+ = {"
									+ toVectorString(baoDongTapThuocTinh)
									+ "}\n\n");
						if (tapCon(baoDongTapThuocTinh, tapThuocTinh)
								&& tapCon(tapThuocTinh, baoDongTapThuocTinh)) {
							if (iShhow)
								showHere.append("  ●●  Dừng giải thuật do ("
										+ toVectorString(tapConThuocTinh)
										+ ")+ bằng tập thuộc tính.\n\n  ●●  Vậy ("
										+ toVectorString(tapConThuocTinh)
										+ ")+ ={"
										+ toVectorString(baoDongTapThuocTinh)
										+ "}");
							return baoDongTapThuocTinh;
						}
					} else {

						if (iShhow)
							showHere.append("           " + "("
									+ toVectorString(tapConThuocTinh)
									+ ")+ = {"
									+ toVectorString(baoDongTapThuocTinh) + "}"
									+ " không chứa vế trái của phu thuộc hàm "
									+ toStringPTH(phuThuocHam)
									+ "\n           ("
									+ toVectorString(tapConThuocTinh)
									+ ")+ = {"
									+ toVectorString(baoDongTapThuocTinh)
									+ "}\n\n");

					}
				} catch (Exception e) {
					JOptionPane.showMessageDialog(null,
							String.valueOf(toStringPTH(phuThuocHam)));
				}
			}
			if ((tapCon(tmp, baoDongTapThuocTinh) && tapCon(
					baoDongTapThuocTinh, tmp))) {
				if (iShhow)
					showHere.append("  ●●  Dừng giải thuật do ("
							+ toVectorString(tapConThuocTinh)
							+ ")+ không thay đổi.\n\n  ●●  Vậy ("
							+ toVectorString(tapConThuocTinh) + ")+ ={"
							+ toVectorString(baoDongTapThuocTinh) + "}");
				return baoDongTapThuocTinh;
			} else {
				if (iShhow)
					showHere.append("  ●●  Duyệt lại tập phụ thuộc hàm do sau khi duyệt tập phụ thuộc hàm thì ("
							+ toVectorString(tapConThuocTinh)
							+ ")+ thay đổi.\n\n");
			}
		}
		return baoDongTapThuocTinh;
	}

	/**
	 * Tìm khóa của lược đồ quan hệ
	 */
	public void timKhoa() {
		if (tapPhuThuocHam.size() == 0)
			return;
		textArea_4.setText("");
		textArea_4
				.append("  ●  Cho quan hệ Q = (" + toVectorString(tapThuocTinh)
						+ ") và tập phụ thuộc hàm F = {");
		for (int i = 0; i < tapPhuThuocHam.size() - 1; i++)
			textArea_4.append(toStringPTH(tapPhuThuocHam.get(i)) + ", ");
		textArea_4
				.append(toStringPTH(tapPhuThuocHam.get(tapPhuThuocHam.size() - 1))
						+ "} . Xác định khóa của Q");
		textArea_4
				.append("\n  ●  Gọi :\n    "
						+ "N : Tập các thuộc tính không chứa trong vế phải\n    "
						+ "M : Tập các thuộc tính vừa trong vế phải vừa trong vế trái của tập phụ thuộc hàm\n    "
						+ "NPlus : Bao đóng của N\n    "
						+ "TapConM : Chứa tất cả tập con của M\n    "
						+ "K : Tập khóa");
		// tập nguồn N chứa các thuộc tính ko có trong về phải
		Vector<String> N = new Vector<String>();

		// tập inVePhai chứa các thuộc tính chứa trong vế phải
		Vector<String> inVePhai = new Vector<String>();
		for (String thuocTinh : tapThuocTinh) {
			for (Vector<Vector<String>> phuThuocHam : tapPhuThuocHam) {
				if (phuThuocHam.get(1).contains(thuocTinh)) {
					inVePhai.add(thuocTinh);
					break;
				}
			}
		}
		for (String thuocTinh : tapThuocTinh) {
			if (!inVePhai.contains(thuocTinh))
				N.add(thuocTinh);
		}

		// tập chứa các thuộc tính vừa thuộc vế phải vừa thuộc vế trái
		Vector<String> M = new Vector<String>();
		for (Vector<Vector<String>> phuThuocHam : tapPhuThuocHam) {
			for (String thuocTinhVeTrai : phuThuocHam.get(0)) {
				for (Vector<Vector<String>> phuThuocHam1 : tapPhuThuocHam) {
					if (phuThuocHam1.get(1).contains(thuocTinhVeTrai)) {
						if (!M.contains(thuocTinhVeTrai)) {
							M.add(thuocTinhVeTrai);
							break;
						}
					}
				}
			}
		}
		// Bao đóng của tập N
		Vector<String> NPlus = timBaoDongTapThuocTinh(N, tapPhuThuocHam, false,
				null);
		textArea_4.append("\n  ●  Ta có : ");
		textArea_4.append("\n    N = {"
				+ ((N.size() != 0) ? toVectorString(N) : "Rỗng")
				+ "}\n    M = {"
				+ ((M.size() != 0) ? toVectorString(M) : "Rỗng") + "}"
				+ "\n    NPlus = {"
				+ ((NPlus.size() != 0) ? toVectorString(NPlus) : "") + "}");
		if (!(tapCon(NPlus, tapThuocTinh) & tapCon(tapThuocTinh, NPlus))) {
			textArea_4.append("\n    NPlus không bằng tập thuộc tính.");
			binary = new int[M.size()];
			Vector<Vector<String>> tapKhoa = new Vector<Vector<String>>();
			Vector<Vector<String>> tapConM = new Vector<Vector<String>>();
			sinhTapCon(0, M, tapConM);
			textArea_4.append("\n  ●  TapConM = ");
			textArea_4.append("\n    {Rỗng}");
			for (int i = 1; i <= tapConM.size() - 1; i++) {
				textArea_4.append("\n    {" + toVectorString(tapConM.get(i))
						+ "}");
			}

			textArea_4.append("\n  ●  Duyệt TapConM và xậy dựng tập khóa : ");
			textArea_4.append("\n    K = {Rỗng}");
			for (Vector<String> conM : tapConM) {
				Vector<String> khoaTam = new Vector<String>();
				khoaTam.addAll(N);
				khoaTam.addAll(conM);
				Vector<String> baoDongKhoaTam = timBaoDongTapThuocTinh(khoaTam,
						tapPhuThuocHam, false, null);
				textArea_4
						.append("\n    {"
								+ ((conM.size() != 0) ? toVectorString(conM)
										: "Rỗng")
								+ "} <Giao> N = {"
								+ ((khoaTam.size() != 0) ? toVectorString(khoaTam)
										: "Rỗng")
								+ "}\n        Bao đóng : {"
								+ ((baoDongKhoaTam.size() != 0) ? toVectorString(baoDongKhoaTam)
										: "Rỗng") + "}");
				if (tapCon(baoDongKhoaTam, tapThuocTinh)
						&& tapCon(tapThuocTinh, baoDongKhoaTam)) {
					textArea_4.append("\n        Bằng tập thuộc tính");
					boolean themKhoa = true;
					for (Vector<String> khoa : tapKhoa) {
						if (tapCon(khoa, khoaTam)) {
							themKhoa = false;
							break;
						}
					}
					if (themKhoa) {
						textArea_4
								.append("\n        Khóa chưa tồn tại. Thêm khóa {"
										+ toVectorString(khoaTam)
										+ "} vào tập khóa");
						tapKhoa.add(khoaTam);
						textArea_4.append("\n        K = ");

						for (int i = 0; i < tapKhoa.size(); i++) {
							textArea_4.append("{"
									+ toVectorString(tapKhoa.get(i)) + "}"
									+ ((i != tapKhoa.size() - 1) ? " , " : ""));
						}
					} else {
						textArea_4.append("\n        {"
								+ toVectorString(khoaTam) + "} là siêu khóa");
					}
				}
			}
			textArea_4.append("\n  ●  Các khóa tìm được là: ");
			for (Vector<String> khoa : tapKhoa) {
				textArea_4.append("\n    " + toVectorString(khoa));
			}
		} else {
			textArea_4.append("\n    NPlus bằng tập thuộc tính.");
			textArea_4.append("\n  ●  Khóa chỉ định duy nhất là: \n    "
					+ toVectorString(N));
			Vector<Vector<String>> tapConKhoa = new Vector<Vector<String>>();
			binary = new int[N.size()];
			sinhTapCon(0, N, tapConKhoa);
			Vector<Vector<String>> tapKhoaTam = new Vector<Vector<String>>();
			for (Vector<String> con : tapConKhoa) {
				if (con.size() == 0)
					continue;
				Vector<String> baoDong = new Vector<String>();
				baoDong = timBaoDongTapThuocTinh(con, tapPhuThuocHam, false,
						null);
				if (tapCon(tapThuocTinh, baoDong)
						&& tapCon(baoDong, tapThuocTinh)) {
					boolean themKhoa = true;
					for (Vector<String> con1 : tapKhoaTam) {
						if (tapCon(con1, con))
							themKhoa = false;
					}
					if (themKhoa) {
						tapKhoaTam.add(con);
					}
				}
			}
			textArea_4
					.append("\n  ●  Kiểm tra tập con của N ta tìm được khóa :");
			for (Vector<String> con : tapKhoaTam)
				textArea_4.append("\n    " + toVectorString(con));
		}
	}

	public JFileChooser getFileChooser(String title) {
		String currentDir = System.getProperty("user.dir");
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.setDialogTitle(title);
		fileChooser.setFileHidingEnabled(false);
		fileChooser.setCurrentDirectory(new File(currentDir));

		FileFilter fil = new FileFilter() {
			@Override
			public boolean accept(File f) {
				if (f.isDirectory()) {
					return true;
				}
				String path = f.getAbsolutePath();

				if (path != null) {
					if (path.endsWith(".dat")) {
						return true;
					}
				}
				return false;
			}

			@Override
			public String getDescription() {
				return "Data file (*.dat)";
			}
		};

		fileChooser.setFileFilter(fil);
		return fileChooser;
	}
}
